#include <iostream>
#include <opencv2/core/core.hpp>
#include <ceres/ceres.h>
#include <chrono>

using namespace std;

// 代价函数的计算模型
struct CURVE_FITTING_COST
{
    CURVE_FITTING_COST ( double x, double y ) : _x ( x ), _y ( y ) {}
    // 残差的计算
    template <typename T>
    bool operator() (
        const T* const a,const T* const b,const T* const c,     // 模型参数，有q=3组参数块，每组参数块维度为s_1=s_2=s_3=1
        T* residual ) const     // 残差
    {
        residual[0] = T ( _y ) - ceres::exp ( a[0]*T ( _x ) *T ( _x ) + b[0]*T ( _x ) + c[0] ); // y-exp(ax^2+bx+c)
        return true;
    }
    const double _x, _y;    // x,y数据
};


int main(int argc, char **argv) {
    
    double a=1.0, b=2.0, c=1.0;         // 真实参数值
    int N=100;                          // 数据点
    double w_sigma=1.0;                 // 噪声Sigma值
    cv::RNG rng;                        // OpenCV随机数产生器
    double a1=0,b1=0,c1=0;            // a,b,c参数的估计值
    
    vector<double> xData,yData;
    
    for(int i=0;i<N;i++){
        double x = i/100.0;
        xData.push_back(x);
        yData.push_back(ceres::exp(a*x*x+b*x+c)+rng.gaussian(w_sigma));
        cout<<xData[i]<<" "<<yData[i]<<endl;
    }
    
    ceres::Problem problem;
    for(int i=0;i<N;i++){
        problem.AddResidualBlock(
            new ceres::AutoDiffCostFunction<CURVE_FITTING_COST,1,1,1,1>(
                new CURVE_FITTING_COST(xData[i],yData[i])
            ),
            nullptr,
            &a1,&b1,&c1
        );
    }
    
    ceres::Solver::Options options;
    options.linear_solver_type = ceres::DENSE_QR;
    options.minimizer_progress_to_stdout = true;
    
    ceres::Solver::Summary summary;
    ceres::Solve(options,&problem,&summary);
    
    cout<<summary.BriefReport()<<endl;
    cout<<"a b c "<<a1<<b1<<c1;
    
    std::cout << "Hello, world!" << std::endl;
    return 0;
}
